import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from PIL import Image


class GPSInfo:
    def __init__(self, lon, lat, p_ang, v=None, img_path=None):
        self.lon = lon
        self.lat = lat
        self.p_ang = p_ang
        self.img_path = img_path
        self.v = v


def image_processing(img_path):
    img = Image.open(img_path).convert('LA')
    # shrink the image to the training size
    img = img.resize((192, 109))  # (width/10, height/10)
    # cut the upper half of image
    img = np.array(img)[:, :, 0]
    img = img[0:54, :].reshape(1, -1)
    return img


def d2r(degree):
    return degree / 180 * np.pi


def r2d(rad):
    return rad / np.pi * 180


def cal_dist(x1, y1, x2, y2):
    return np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)


def projection(x, y, x1, y1, x2, y2):
    """
    https://www.cnblogs.com/flyinggod/p/9359534.html
    """
    cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1)
    if cross <= 0:  # 投影到x1,y1上
        projection_status = 1
        px, py = x1, y1
    else:
        d2 = (x1 - x2) ** 2 + (y1 - y2) ** 2
        if cross >= d2:  # 投影到x2,y2上
            projection_status = 2
            px, py = x2, y2
        else:  # 投影到中间
            projection_status = 0
            r = cross / d2
            px = x1 + (x2 - x1) * r
            py = y1 + (y2 - y1) * r
    return px, py, cal_dist(x, y, px, py), projection_status


def projection_pl(x, y, pt_list):
    """
    return x_proj, y_proj, dist_from_snode, min_dist_proj, projection_status
    Parameters
    ----------
    x
    y
    pt_list

    Returns
    -------
    x_proj, y_proj, dist_from_snode, min_dist_proj, projection_status
    """
    assert type(pt_list) == list
    n = len(pt_list)
    min_dist_proj = 999
    mini = 0

    for i in range(0, n - 1):
        x_proj_temp, y_proj_temp, dist_proj, projection_status = projection(x, y, pt_list[i][0], pt_list[i][1],
                                                                            pt_list[i+1][0], pt_list[i+1][1])
        if dist_proj < min_dist_proj:
            min_dist_proj = dist_proj
            mini = i
            x_proj = x_proj_temp
            y_proj = y_proj_temp
            if projection_status == 0 and min_dist_proj < 0.00026:  # 因为很少有大拐弯的路段，为了加快速度直接跳出。
                break

    # 计算距起点的距离
    # 计算投影点->投影点前一节点的距离
    dist_from_snode = cal_dist(pt_list[mini][0], pt_list[mini][1], x_proj, y_proj)
    # 计算前若干段线段的距离
    for i in range(0, mini):
        dist_from_snode += cal_dist(pt_list[i][0], pt_list[i][1], pt_list[i + 1][0], pt_list[i + 1][1])

    return x_proj, y_proj, dist_from_snode, min_dist_proj, projection_status


def plot_proj(x, y, x1, y1, x2, y2):
    plt.axis('equal')
    plt.plot([x1, x2], [y1, y2])
    plt.scatter(x, y)
    plt.text(x1, y1, "s")


def is_obtuse_angle(angle_deg):
    if np.cos(d2r(angle_deg)) < 0:
        return True
    else:
        return False


def score_label(result_path, groundtruth_path, interval, skip, log_path, time_cost, conn, datatable, latency=None):
    result_df = pd.read_csv(result_path)
    pt_num = result_df.shape[0]
    groundtruth_df = pd.read_csv(groundtruth_path)

    # remove duplicated edges from ground truth data
    groundtruth_df.drop_duplicates(subset='trueroad', inplace=True)
    groundtruth_edge = groundtruth_df['trueroad'].unique()
    gt_len = groundtruth_df['length'].sum()

    # remove duplicated edges from result
    result_df.drop_duplicates(subset='rid', inplace=True)
    result = result_df['rid'].values
    cmdstr = f"select length from {datatable} where id in ('" + "','".join(
        result_df['rid'].astype('str').values) + "')"
    temp_df = pd.read_sql(cmdstr, conn)
    temp_df["length"] = temp_df["length"].astype(float)
    match_len = temp_df["length"].sum()

    # length-weighed sum
    correct_len = 0
    for each in result:
        if each in groundtruth_edge:
            correct_len += groundtruth_df[groundtruth_df['trueroad'] == each]['length'].values[0]
    producer_accuracy = correct_len / gt_len
    user_accuracy = correct_len / match_len

    # write result
    with open(log_path, "a") as f:
        if latency:
            f.write(f"{latency},")
        f.write(
            f"{interval},{skip},{correct_len},{gt_len},{match_len},{producer_accuracy},{user_accuracy},{time_cost},"
            f"{pt_num}\n")
        f.flush()

    print("correct_len = ", correct_len)
    print("gt_len = ", gt_len)
    print("match_len = ", match_len)
    print("prod: correct/gt = ", producer_accuracy)
    print("user: correct/match = ", user_accuracy)
    print("elapsed time:", time_cost)
    print("time per point(ms):", time_cost * 1000 / pt_num)
